# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# pyre-strict

import typing
from collections.abc import (
    ItemsView,
    Iterator,
    KeysView,
    MutableMapping,
    MutableSequence,
    MutableSet as MutableSetAbc,
    ValuesView,
)
from typing import (
    Any,
    Generic,
    Iterable,
    List,
    Mapping,
    Optional,
    overload,
    Protocol,
    Tuple,
    TypeVar,
    Union,
)

from thrift.python.mutable_types import (
    _ThriftListWrapper,
    _ThriftMapWrapper,
    _ThriftSetWrapper,
)

T = TypeVar("T")

class MutableList(MutableSequence[T]):
    def __init__(
        self,
        typeinfo: object,
        list_data: List[T],
    ) -> None: ...
    def __len__(self) -> int: ...
    @overload
    def __getitem__(self, index: int) -> T: ...
    @overload
    # pyre-fixme[24]: Generic type `slice` expects 3 type parameters.
    def __getitem__(self, index: slice) -> MutableList[T]: ...
    @overload
    def __setitem__(self, index: int, value: T) -> None: ...
    @overload
    def __setitem__(
        self: MutableList[MutableList[Any]],
        index: int,
        value: T | _ThriftListWrapper,
    ) -> None: ...
    @overload
    def __setitem__(
        self: MutableList[MutableSet[Any]], index: int, value: T | _ThriftSetWrapper
    ) -> None: ...
    @overload
    def __setitem__(
        self: MutableList[MutableMap[Any, Any]],
        index: int,
        value: T | _ThriftMapWrapper,
    ) -> None: ...
    @overload
    def __delitem__(self, index: int) -> None: ...
    @overload
    # pyre-fixme[24]: Generic type `slice` expects 3 type parameters.
    def __delitem__(self, index: slice) -> None: ...
    @overload
    def insert(self, index: int, value: T) -> None: ...
    @overload
    def insert(
        self: MutableList[MutableList[Any]],
        index: int,
        value: T | _ThriftListWrapper,
    ) -> None: ...
    @overload
    def insert(
        self: MutableList[MutableSet[Any]], index: int, value: T | _ThriftSetWrapper
    ) -> None: ...
    @overload
    def insert(
        self: MutableList[MutableMap[Any, Any]],
        index: int,
        value: T | _ThriftMapWrapper,
    ) -> None: ...
    @overload
    def append(self, value: T) -> None: ...
    @overload
    def append(
        self: MutableList[MutableList[Any]], value: T | _ThriftListWrapper
    ) -> None: ...
    @overload
    def append(
        self: MutableList[MutableSet[Any]], value: T | _ThriftSetWrapper
    ) -> None: ...
    @overload
    def append(
        self: MutableList[MutableMap[Any, Any]], value: T | _ThriftMapWrapper
    ) -> None: ...
    @overload
    def extend(self, values: Iterable[T]) -> None: ...
    @overload
    def extend(
        self: MutableList[MutableList[Any]],
        values: Iterable[T | _ThriftListWrapper],
    ) -> None: ...
    @overload
    def extend(
        self: MutableList[MutableSet[Any]],
        values: Iterable[T | _ThriftSetWrapper],
    ) -> None: ...
    @overload
    def extend(
        self: MutableList[MutableMap[Any, Any]],
        values: Iterable[T | _ThriftMapWrapper],
    ) -> None: ...
    def pop(self, index: int = -1) -> T: ...
    def clear(self) -> None: ...
    @overload
    def __add__(self, other: Iterable[T]) -> MutableList[T]: ...
    @overload
    def __add__(
        self: MutableList[MutableList[Any]], other: Iterable[T | _ThriftListWrapper]
    ) -> MutableList[T]: ...
    @overload
    def __add__(
        self: MutableList[MutableSet[Any]], other: Iterable[T | _ThriftSetWrapper]
    ) -> MutableList[T]: ...
    @overload
    def __add__(
        self: MutableList[MutableMap[Any, Any]],
        other: Iterable[T | _ThriftMapWrapper],
    ) -> MutableList[T]: ...
    def __radd__(self, other: Iterable[T]) -> MutableList[T]: ...
    def count(self, value: object) -> int: ...
    def index(
        self,
        value: object,
        start: Optional[int | typing.SupportsIndex] = 0,
        stop: Optional[int | typing.SupportsIndex] = None,
    ) -> int: ...
    def __contains__(self, value: object) -> bool: ...

class MutableSet(MutableSetAbc[T]):
    def __init__(
        self,
        typeinfo: object,
        set_data: typing.Set[object],
    ) -> None: ...
    def __len__(self) -> int: ...
    def __contains__(self, x: object) -> bool: ...
    def __iter__(self) -> ValueIterator[T]: ...
    def isdisjoint(self, other: typing.Iterable[object]) -> bool: ...
    def __le__(self, other: typing.Iterable[object]) -> bool: ...
    def __lt__(self, other: typing.Iterable[object]) -> bool: ...
    def __ge__(self, other: typing.Iterable[object]) -> bool: ...
    def __gt__(self, other: typing.Iterable[object]) -> bool: ...
    def __and__(self, other: typing.Iterable[object]) -> MutableSet[T]: ...
    # pyre-ignore[15]: Inconsistent override
    def __or__(self, other: typing.Iterable[object]) -> MutableSet[T]: ...
    def __sub__(self, other: typing.Iterable[object]) -> MutableSet[T]: ...
    def __xor__(self, other: typing.Iterable[object]) -> MutableSet[T]: ...
    def add(self, value: T) -> None: ...
    def discard(self, value: T) -> None: ...
    def remove(self, value: T) -> None: ...
    def pop(self) -> T: ...
    def clear(self) -> None: ...
    @classmethod
    def _from_iterable(
        cls,
        typeinfo: object,
        set_data: typing.Set[object],
        it: typing.Iterable[object],
    ) -> MutableSet[T]: ...

class ValueIterator(Iterator[T]):
    def __init__(
        self,
        typeinfo: object,
        set_data: typing.Set[object],
    ) -> None: ...
    def __next__(self) -> T: ...
    def __iter__(self) -> ValueIterator[T]: ...

K = TypeVar("K")
V = TypeVar("V")
_K = TypeVar("_K")
_V = TypeVar("_V")

class SupportsKeysAndGetItem(Protocol[K, V]):
    def keys(self) -> Iterable[K]: ...
    def __getitem__(self, k: K) -> V: ...

class MutableMap(MutableMapping[K, V]):
    def __init__(
        self,
        key_typeinfo: object,
        val_typeinfo: object,
        map_data: Mapping[object, object],
    ) -> None: ...
    def __len__(self) -> int: ...
    def __getitem__(self, key: K) -> V: ...
    def __iter__(self) -> ValueIterator[K]: ...
    @overload
    def get(self, key: K, /) -> V | None: ...
    @overload
    def get(self, key: K, /, default: V | _T) -> V | _T: ...
    @overload
    def __setitem__(self, key: K, value: V) -> None: ...
    @overload
    def __setitem__(
        self: MutableMap[K, MutableList[_V]],
        key: K,
        value: MutableList[_V] | _ThriftListWrapper,
    ) -> None: ...
    @overload
    def __setitem__(
        self: MutableMap[K, MutableSet[_V]],
        key: K,
        value: MutableSet[_V] | _ThriftSetWrapper,
    ) -> None: ...
    @overload
    def __setitem__(
        self: MutableMap[K, MutableMap[_K, _V]],
        key: K,
        value: MutableMap[_K, _V] | _ThriftMapWrapper,
    ) -> None: ...
    def __delitem__(self, key: K) -> None: ...
    def __contains__(self, key: T) -> bool: ...
    @overload
    def update(self, m: SupportsKeysAndGetItem[K, V], /, **kwargs: V) -> None: ...
    @overload
    def update(self, m: Mapping[K, V], /, **kwargs: V) -> None: ...
    @overload
    def update(self, m: Iterable[tuple[K, V]], /, **kwargs: V) -> None: ...
    @overload
    def update(self, **kwargs: V) -> None: ...
    @overload
    def pop(self, key: K, /) -> V: ...
    @overload
    def pop(self, key: K, /, default: V) -> V: ...
    @overload
    def pop(self, key: K, /, default: T) -> V | T: ...
    def popitem(self) -> Tuple[K, V]: ...
    def clear(self) -> None: ...
    def keys(self) -> MapKeysView[K]: ...
    def items(self) -> MapItemsView[K, V]: ...
    def values(self) -> MapValuesView[V]: ...
    @overload
    def setdefault(self, key: K, default: V, /) -> V: ...
    @overload
    def setdefault(
        self: MutableMap[K, _V | None], key: K, default: None = None, /
    ) -> _V | None: ...
    @overload
    def setdefault(
        self: MutableMap[K, MutableList[_V]], key: K, default: V | _ThriftListWrapper, /
    ) -> V: ...
    @overload
    def setdefault(
        self: MutableMap[K, MutableSet[_V]], key: K, default: V | _ThriftSetWrapper, /
    ) -> V: ...
    @overload
    def setdefault(
        self: MutableMap[K, MutableMap[_K, _V]],
        key: K,
        default: V | _ThriftMapWrapper,
        /,
    ) -> V: ...

class MapKeysView(KeysView[K]):
    def __len__(self) -> int: ...
    def __contains__(self, key: object) -> bool: ...
    @overload
    def __iter__(self) -> Iterator[K]: ...
    @overload
    def __iter__(self: MapKeysView[K]) -> Iterator[K]: ...

class MapItemsView(ItemsView[K, V]):
    def __len__(self) -> int: ...
    def __contains__(self, item: object) -> bool: ...
    @overload
    def __iter__(self) -> Iterator[tuple[K, V]]: ...
    @overload
    def __iter__(self: ItemsView[K, V]) -> Iterator[tuple[K, V]]: ...

class MapItemIterator(Iterator[T]):
    def __next__(self) -> T: ...
    def __iter__(self) -> MapItemIterator[T]: ...

class MapValuesView(ValuesView[V]):
    def __len__(self) -> int: ...
    @overload
    def __iter__(self) -> Iterator[V]: ...
    @overload
    def __iter__(self: ValuesView[V]) -> Iterator[V]: ...
